package com.lime49.lockcrypt;

import com.lime49.lockcrypt.ui.AbstractDialog;
import com.lime49.lockcrypt.ui.DropDownButton;
import com.lime49.lockcrypt.ui.MouseMenuItem;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ResourceBundle;
import org.json.JSONObject;

/**
 * A form for configuring AutoType
 */
public class FrmAutoType extends AbstractDialog implements ILanguageParent {
    private ILanguageParent owner;
    private boolean recording = false;
    
    private JComboBox cboWindowName;
    private JTextArea txtConfig;
    private JButton btnRecord;
    private AutoTyper autoTyper = new AutoTyper(this);
    private ArrayList<String> fields;
    
    private int FRAMEWIDTH = 450;
    
    public FrmAutoType(ILanguageParent owner, ArrayList<String> fields) {
        this(owner, "", fields);
    }
    public FrmAutoType(ILanguageParent owner, String config, ArrayList<String> fields) {
        super(owner instanceof JDialog ? (JDialog)owner : null, owner.getLanguage().getString("AUTOTYPE"), true);
        this.owner = owner;
        this.fields = fields;
        if(!autoTyper.canConnect()) {
            dispose();
            return;
        }
        KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
        Action escapeAction = new AbstractAction() {
            // cancel the dialog when the user presses escape
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        }; 
        this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
        this.getRootPane().getActionMap().put("ESCAPE", escapeAction);
        JPanel content = new JPanel(new GridBagLayout());
            this.setContentPane(content);
            content.setBorder(Constants.EMPTYBORDER);
            GridBagConstraints c = new GridBagConstraints();
            c.insets = Constants.GLOBALINSETS;
            int cury = 0;
        
        Utils.setgrid(c,cury,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
        JLabel lblTargetWindow = new JLabel(owner.getLanguage().getString("TARGETWINDOW")+":");
            lblTargetWindow.setMinimumSize(new Dimension(80,10));
            content.add(lblTargetWindow,c);
        cboWindowName = new JComboBox(autoTyper.getWindows());
            lblTargetWindow.setLabelFor(cboWindowName);
            cboWindowName.setEditable(true);
            cboWindowName.setRenderer(new WindowListRenderer());
        Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.WEST,1);
            content.add(cboWindowName,c);
            cury++;
            
        Utils.setgrid(c,cury,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
        JLabel lblGeneratedConfig = new JLabel(owner.getLanguage().getString("CONFIGURATION")+":");
            content.add(lblGeneratedConfig,c);
        Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.BOTH,GridBagConstraints.NORTHWEST,1);
            txtConfig = new JTextArea("",4,15);
            txtConfig.setLineWrap(true);
            txtConfig.setWrapStyleWord(true);
            JScrollPane scrollConfig = new JScrollPane(txtConfig);
            lblGeneratedConfig.setLabelFor(txtConfig);
            c.weighty = 1;
            content.add(scrollConfig,c);
            cury++;
            
        JPanel buttonBox = new JPanel();
            buttonBox.setLayout(new BoxLayout(buttonBox, BoxLayout.LINE_AXIS));
            JButton btnTools = new JButton(owner.getLanguage().getString("MNU_TOOLS"));
            final JPopupMenu mnuTools = new JPopupMenu();
            MouseMenuItem itmHelp = new MouseMenuItem(owner.getLanguage().getString("MNU_HELP"));
            MouseMenuItem itmInsertDelay = new MouseMenuItem(owner.getLanguage().getString("INSERTDELAY"));
            //MouseMenuItem itmInsertField = new MouseMenuItem(owner.getLanguage().getString("INSERTFIELD"));
            JMenu mnuInsertField = new JMenu(owner.getLanguage().getString("INSERTFIELD"));
            final ILanguageParent fOwner = owner;
            itmHelp.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        if(new File(Utils.getJARPath()+"\\LockCrypt.chm").exists()) {
                            Runtime.getRuntime().exec("hh.exe -mapid 15561 "+Utils.getJARPath()+"\\LockCrypt.chm");
                        } else if(new File(System.getProperty("user.dir")+"\\LockCrypt.chm").exists()) {
                            Runtime.getRuntime().exec("hh.exe -mapid 15561 "+System.getProperty("user.dir")+"\\LockCrypt.chm");
                        } else if(new File(System.getProperty("ProgramFiles")+"\\LockCrypt.chm").exists()) {
                            Runtime.getRuntime().exec("hh.exe -mapid 15561 "+System.getProperty("ProgramFiles")+"\\LockCrypt\\LockCrypt.chm");
                        } else if(new File(System.getProperty("ProgramFiles(x86)")+"\\LockCrypt.chm").exists()) {
                            Runtime.getRuntime().exec("hh.exe -mapid 15561 "+System.getProperty("ProgramFiles(x86)")+"\\LockCrypt\\LockCrypt.chm");
                        } else {
                            JOptionPane.showMessageDialog(null, fOwner.getLanguage().getString("ERROR")+"#214: "+fOwner.getLanguage().getString("ERR_HELPNOTFOUND"), fOwner.getLanguage().getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                        }
                    } catch(IOException er) {
                        JOptionPane.showMessageDialog(null, fOwner.getLanguage().getString("ERROR")+"#213: "+fOwner.getLanguage().getString("ERR_HELPNOTFOUND"), fOwner.getLanguage().getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                    }
                }
            });
            itmInsertDelay.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    FrmPromptDelay frmPromptDelay = new FrmPromptDelay((ILanguageParent)thisDialog);
                    if(frmPromptDelay.getResult() == JOptionPane.OK_OPTION) {
                        txtConfig.insert("{Wait:"+frmPromptDelay.getDelay()+"}", txtConfig.getCaretPosition());
                    }
                }
            });
            InsertFieldListener insertFieldListener = new InsertFieldListener();
            for(String fieldName : fields) {
                JMenuItem itmField = new JMenuItem(fieldName);
                itmField.addActionListener(insertFieldListener);
                itmField.setActionCommand(fieldName);
                mnuInsertField.add(itmField);
            }
            mnuTools.add(itmInsertDelay);
            mnuTools.add(mnuInsertField);
            mnuTools.add(itmHelp);
            final DropDownButton btnDDTools = new DropDownButton(btnTools, SwingConstants.SOUTH, mnuTools);
            btnDDTools.getMenu().setInvoker(this);
            btnRecord = new JButton(owner.getLanguage().getString("RECORDACTION"));
            JButton btnSave = new JButton(owner.getLanguage().getString("SAVE"));
            JButton btnCancel = new JButton(owner.getLanguage().getString("CANCEL"));
            btnTools.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    btnDDTools.showMenu(e);
                }
            });;
            btnRecord.addActionListener(new StartRecordListener());
            btnSave.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if(validateAutoType()) {
                        result = JOptionPane.OK_OPTION;
                        dispose();
                    }
                }
            });
            btnCancel.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                   dispose();
               }
            });
            buttonBox.add(btnDDTools);
            buttonBox.add(Box.createHorizontalStrut(10));
            buttonBox.add(btnRecord);
            buttonBox.add(Box.createHorizontalGlue());
            buttonBox.add(btnSave);
            buttonBox.add(Box.createHorizontalStrut(10));
            buttonBox.add(btnCancel);
            btnDDTools.setMinimumSize(Constants.MINSIZE);
            btnDDTools.setPreferredSize(Constants.PREFSIZE);
            btnDDTools.setMaximumSize(Constants.MAXSIZE);
            btnSave.setMinimumSize(Constants.MINSIZE);
            btnSave.setPreferredSize(Constants.PREFSIZE);
            btnSave.setMaximumSize(Constants.MAXSIZE);
            btnCancel.setMinimumSize(Constants.MINSIZE);
            btnCancel.setPreferredSize(Constants.PREFSIZE);
            btnCancel.setMaximumSize(Constants.MAXSIZE);
        c.weighty = 0;
        Utils.setgrid(c,cury,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.WEST,1.5);
            content.add(buttonBox,c);
        this.getRootPane().setDefaultButton(btnSave);
        
        parseConfig(config);
        this.setMinimumSize((new Dimension(300,200)));
        this.setPreferredSize((new Dimension(FRAMEWIDTH,330)));
        this.pack();
        this.setLocationRelativeTo(owner.getParentWindow());
        this.setVisible(true);
    }
    
    /*============================ ILanguageParent ==========================*/
    /**
     * Returns the current language ResourceBundle
     * @return The current language ResourceBundle
     */
    public ResourceBundle getLanguage() {
        return owner.getLanguage();
    }
    
    public Component getParentWindow() {
        return thisDialog;
    }
    
    public boolean getDebug() {
        return owner.getDebug();
    }
    /*============================ End ILanguageParent ==========================*/
      
    /**
    * Returns the JOptionPane result from this dialog
    * @return JOptionPane.OK_MESSAGE or JOptionPanel.CANCEL_MESSAGE
    */
    public String getConfig() {
        JSONObject jsoConfig = new JSONObject();
        try {
            jsoConfig.put("target", cboWindowName.getSelectedItem().toString());
            jsoConfig.put("config", txtConfig.getText());
        } catch(Exception ignore) {}
        return jsoConfig.toString();
    }
    
    /**
     * Parses the autotype configuration and selects the correct window from the combobox
     */
    private void parseConfig(String config) {
        try {
            JSONObject jsoConfig = new JSONObject(config);
            cboWindowName.setSelectedItem(jsoConfig.getString("target"));
            txtConfig.setText(jsoConfig.getString("config"));
        } catch(Exception ignore) {}
    }
    
    /**
     * Checks a window title is entered and the configuration is not blank
     * @return True if the configuration is valid, otherwise false
     */
    private boolean validateAutoType() {
        boolean valid = true;
        if(cboWindowName.getSelectedItem().toString().trim().length() == 0) {
            valid = false;
            JOptionPane.showMessageDialog(thisDialog, owner.getLanguage().getString("ERR_WINDOWNAMEBLANK"));
        } else if(txtConfig.getText().trim().length() == 0) {
            valid = false;
            JOptionPane.showMessageDialog(thisDialog, owner.getLanguage().getString("ERR_CONFIGBLANK"));
        }
        return valid;
    }
    
    /**
     * Signals the helper application to start recording keystrokes and mouse actions
     */
    private void startRecording() {
        recording = true;
        btnRecord.setText(owner.getLanguage().getString("STOPRECORDING"));
        autoTyper.recordAction();
    }
    
    /**
     * Stops recording keystrokes and mouse actions
     */
    private void stopRecording() {
        recording = false;
        btnRecord.setText(owner.getLanguage().getString("RECORDACTION"));
        txtConfig.setText(autoTyper.getRecordedAction());
    }
    
    /**
     * Starts recording keystrokes and changes the 'Record' button to 'Stop Recording' button
     */
    private class StartRecordListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            btnRecord.removeActionListener(this);
            btnRecord.addActionListener(new StopRecordListener());
            startRecording();
        }
    }
    
    /**
     * Stops recording keystrokes and changes the 'Stop Recording' button to 'Record' button
     */
    private class StopRecordListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            if(recording) {
                btnRecord.removeActionListener(this);
                btnRecord.addActionListener(new StartRecordListener());
                stopRecording();
            }
        }
    }
    
    class WindowListRenderer extends JLabel implements ListCellRenderer {
        protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            JLabel lbl = (JLabel)defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            String text = value.toString();
            if(text.length() > 55) {
                lbl.setText("<HTML>"+text.substring(0,52)+"...</HTML>");
            } else {
                lbl.setText("<HTML>"+text+"</HTML>");
            }
            lbl.setMaximumSize(new Dimension(FRAMEWIDTH-100, 20));//list.getFont().getSize()
            if(!isSelected) {
              lbl.setForeground(list.getForeground());
            }
            //return this;
            return lbl;
        }
    }
    
    class InsertFieldListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            txtConfig.insert("$"+e.getActionCommand()+"$", txtConfig.getCaretPosition());
        }
    }
}
